package cn.zwk.template;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import org.springframework.util.StringUtils;

import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;

public final class FreemarkerRenderer {
    private static final Configuration CFG;

    static {
        CFG = new Configuration(Configuration.VERSION_2_3_32);
        CFG.setDefaultEncoding(StandardCharsets.UTF_8.name());
        CFG.setOutputEncoding(StandardCharsets.UTF_8.name());
        CFG.setURLEscapingCharset(StandardCharsets.UTF_8.name());
        CFG.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        CFG.setLogTemplateExceptions(false);
        CFG.setWrapUncheckedExceptions(true);
        CFG.setFallbackOnNullLoopVariable(false);
    }

    private FreemarkerRenderer() {
    }

    public static String renderString(String template, Map<String, Object> model) {
        if (template == null) return null;
        Map<String, Object> jsonMap = new LinkedHashMap<>();
        model.forEach((k, v) -> {
            if (v instanceof String) {
                jsonMap.put(k, tryToJson(String.valueOf(v)));
            }else {
                jsonMap.put(k, v);
            }
        });
        try {
            Template t = new Template("inline", new StringReader(template), CFG);
            StringWriter out = new StringWriter();
            t.process(model == null ? Map.of() : jsonMap, out);
            return out.toString();
        } catch (Exception e) {
            throw new RuntimeException("Freemarker render error", e);
        }
    }

    public static Object tryToJson(String str){
        if (!StringUtils.hasText(str)) return "";
        try {
            return JSONObject.parse(str);
        } catch (Exception e1) {
            try {
                return JSONArray.parse(str);
            } catch (Exception e2) {
                return str;
            }
        }
    }

    public static Map<String, String> renderMap(Map<?, ?> src, Map<String, Object> model) {
        Map<String, String> out = new HashMap<>();
        if (src == null) return out;
        for (Map.Entry<?, ?> e : src.entrySet()) {
            String k = String.valueOf(e.getKey());
            String v = e.getValue() == null ? null : String.valueOf(e.getValue());
            String rk = renderString(k, model);
            String rv = renderString(v, model);
            out.put(rk, rv);
        }
        return out;
    }

    public static List<String> renderList(List<?> src, Map<String, Object> model) {
        List<String> out = new ArrayList<>();
        if (src == null) return out;
        for (Object s : src) {
            out.add(renderString(Objects.toString(s, null), model));
        }
        return out;
    }
}
